package spring.feignHystrix.demo;

import com.netflix.client.ClientException;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class HystrixMain {
    // 测试请求处理执行
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 测试
        Future<String> future1 = new MyHystrixCommand("线程1").queue();
        System.out.println(future1.get());
    }
}

/**
 * 熔断器测试类
 */
class MyHystrixCommand extends HystrixCommand<String> {
    private final String name; // 线程名
    public MyHystrixCommand(String name) {
        // 初始化，配置Hystrix的设置
        super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
                // 信号量策略配置
                // 用于隔离本地代码或可快速返回的远程调用可以直接使用信号量隔离，降低线程隔离的上下文切换开销。如 memcached，redis。
                // 线程隔离会带来线程开销，有些场景（比如无网络请求场景）可能会因为用开销换隔离得不偿失，为此 hystrix 提供了信号量隔离。
                // 主要适用于并发需求不大的依赖调用，因为如果并发需求较大，相应的信号量的数量就要设置得够大，因为 Tomcat 线程与处理线程为同一个线程，那么这个依赖调用就会占用过多的 Tomcat 线程资源，有可能会影响到其他服务的接收。
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))
                // 线程隔离策略配置
                // 执行依赖代码的线程与请求线程（比如 Tomcat 线程）分离，请求线程可以自由控制离开的时间，这也是我们通常说的异步编程，Hystrix 是结合 RxJava 来实现的异步编程。
                // 通过为每个包裹了 HystrixCommand 的 API 接口设置独立的、固定大小的线程池（hystrix.threadpool.default.coreSize）来控制并发访问量，当线程饱和的时候可以拒绝服务，防止依赖问题扩散。
                // 系统默认采用线程隔离策略，我们可以通过 andThreadPoolPropertiesDefaults 配置线程池的一些参数，代码如下所示。
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10).withMaxQueueSize(100).withMaximumSize(100))
        );
        this.name = name;
    }
    // 【重要】执行处理内容
    @Override
    protected String run() throws ClientException {
        if (1==1){
            throw new ClientException("测试异常");
        }
        // 线程执行内容：
        return this.name + ":" + Thread.currentThread().getName();
    }
    // 执行失败
    @Override
    protected String getFallback() {
        return "执行失败！";
    }
}
